package com.novel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.novel.config.RedissonHelper;
import com.novel.constants.ReviewEnum;
import com.novel.entiy.*;
import com.novel.entiy.dto.*;
import com.novel.entiy.event.HotEvent;
import com.novel.entiy.vo.*;
import com.novel.exception.BusinessException;
import com.novel.mapper.*;
import com.novel.service.NovelService;
import com.novel.service.UserService;
import com.novel.utils.ConverterUtil;
import com.novel.utils.MarkdownUtils;
import com.novel.utils.PageResult;
import com.novel.utils.SnowIdUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.redisson.api.RLock;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author tanghao
 * @date 2022/4/7
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NovelServiceImpl implements NovelService {

    private final UserService userService;

    private final NovelMapper novelMapper;

    private final ChapterMapper chapterMapper;

    private final RedissonHelper redissonHelper;

    private final SubscribeMapper subscribeMapper;

    private final TpUserMapper tpUserMapper;

    private final ClassifyMapper classifyMapper;

    private final ScoreRecordMapper scoreRecordMapper;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final ReviewMapper reviewMapper;

    /**
     * 新建小说
     *
     * @param novelDTO 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addNovel(NovelDTO novelDTO) {
        TpUser userInfo = userService.getUserInfo();
        Classify classify = classifyMapper.selectById(novelDTO.getClassifyId());
        Novel novel = novelDTO.doForward();
        long id = SnowIdUtils.uniqueLong();
        novel.setId(id);
        novel.setAuthorId(userInfo.getId());
        novel.setAuthorName(userInfo.getNickname());
        novel.setBrowseNums(0L);
        novel.setWordNums(0L);
        novel.setSubscribeNums(0L);
        novel.setHotNums(0L);
        novel.setStatus(2);
        novel.setCommentNums(0L);
        novel.setChapterNums(0);
        novel.setScoreNums(0);
        novel.setIsCharge(0);
        novel.setClassifyName(classify.getClassifyName());
        novelMapper.insert(novel);

        //建立审批
        Review review = Review.builder().reviewType(ReviewEnum.NOVEL.getType())
                .createdEmail(userInfo.getEmail())
                .createdUser(userInfo.getNickname())
                .createdId(userInfo.getId())
                .reviewResult(0)
                .mainId(id)
                .mainTitle(novel.getTitle() + "-新建小说")
                .build();
        reviewMapper.insert(review);

    }

    /**
     * 获取全部分类
     *
     * @return 分类
     */
    @Override
    public List<Classify> getAllClassify() {
        return classifyMapper.selectList(null);
    }

    /**
     * 首页-获取小说列表
     *
     * @param novelPageDTO 参数
     * @return 小说
     */
    @Override
    public PageResult<Novel> getNovelList(NovelPageDTO novelPageDTO) {
        Page<Novel> pageNovel = novelMapper.getNovelList(
                new Page<>(novelPageDTO.getPageNum(), novelPageDTO.getPageSize(), true), novelPageDTO);
        return new PageResult<>(pageNovel);
    }

    /**
     * 获取小说信息
     *
     * @param id 小说id
     * @return 小说信息
     */
    @Override
    public NovelVO getNovelInfo(Long id) {
        TpUser userInfo;
        try {
            userInfo = userService.getUserInfo();
        } catch (BusinessException e) {
            userInfo = null;
        }
        Novel novel = novelMapper.selectById(id);
        NovelVO novelVO = new NovelVO();
        //获取小说的的三章章节信息
        List<Chapter> chapterList = chapterMapper.selectList(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, id)
                .orderByDesc(Chapter.COL_CHAPTER_NO).last("limit 3"));
        List<ChapterVO> chapterVOList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(chapterList)) {
            chapterVOList = ConverterUtil.convertList(chapterList);
        }
        ConverterUtil.copyPropertiesIgnoreNull(novel, novelVO);
        novelVO.setChapterList(chapterVOList);
        novelVO.setExistBookSelf(Boolean.FALSE);
        //获取当前用户对小说的评分信息
        if (ObjectUtils.isNotEmpty(userInfo)) {
            ScoreRecord record = scoreRecordMapper.selectOne(new QueryWrapper<ScoreRecord>().eq(ScoreRecord.COL_NOVEL_ID, id)
                    .eq(ScoreRecord.COL_USER_ID, userInfo.getId()));
            if (ObjectUtils.isNotEmpty(record)) {
                novelVO.setScoreSelf(record.getScore());
            }
            Long recentReadChapter = novelMapper.getRecentReadChapter(id, userInfo.getId());
            if (ObjectUtils.isNotEmpty(recentReadChapter)) {
                Chapter chapter = chapterMapper.selectById(recentReadChapter);
                novelVO.setRecentChapterId(chapter.getId());
                novelVO.setRecentChapterName(chapter.getChapterName());
            }
            //是否加入书架
            Subscribe subscribe = subscribeMapper.selectOne(
                    new QueryWrapper<Subscribe>().eq(Subscribe.COL_USER_ID, userInfo.getId()).eq(Subscribe.COL_NOVEL_ID, id));
            if (ObjectUtils.isNotEmpty(subscribe)) {
                novelVO.setExistBookSelf(Boolean.TRUE);
            }
        }

        return novelVO;
    }

    /**
     * 编辑小说
     *
     * @param novelDTO 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editNovel(NovelDTO novelDTO) {
        TpUser userInfo = userService.getUserInfo();
        if (ObjectUtils.isEmpty(novelDTO.getId())) {
            log.error("编辑必须传id,参数{}", novelDTO);
            throw new BusinessException("参数有误 ");
        }
        Novel byId = novelMapper.selectById(novelDTO.getId());
        if (ObjectUtils.isEmpty(byId)) {
            log.error("更新小说传的id有误,小说不存在,参数{}", novelDTO.getId());
            throw new BusinessException("参数有误");
        }
        if (byId.getStatus().equals(2)) {
            throw new BusinessException("审核中的小说不能编辑");
        }
        Novel novel = novelDTO.doForward();
        novel.setStatus(2);

        //小说状态为审核中
        novelMapper.updateById(novel);
        //建立审批
        Review review = Review.builder().reviewType(ReviewEnum.NOVEL_EDIT.getType())
                .createdEmail(userInfo.getEmail())
                .createdUser(userInfo.getNickname())
                .createdId(userInfo.getId())
                .reviewResult(0)
                .mainId(novel.getId())
                .mainTitle("《" + novel.getTitle() + "》")
                .build();
        reviewMapper.insert(review);
        //小说编辑前内容入缓存
        redissonHelper.setValue("edit-novel" + novel.getId(), byId);

    }

    /**
     * 删除小说
     *
     * @param id 小说id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delNovel(Long id) {
        novelMapper.deleteById(id);
        chapterMapper.delete(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, id));
    }

    /**
     * 新增章节
     *
     * @param chapterDTO 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addChapter(ChapterDTO chapterDTO) {
        TpUser userInfo = userService.getUserInfo();
        Chapter chapter = chapterDTO.doForward();
        long id = SnowIdUtils.uniqueLong();
        chapter.setId(id);
        //markdown->html
        chapter.setChapterContentHtml(MarkdownUtils.markdownToHtml(chapter.getChapterContentMarkdown()));
        List<Chapter> chapterList = chapterMapper.selectList(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, chapterDTO.getNovelId()));
        if (CollectionUtils.isNotEmpty(chapterList)) {
            chapter.setChapterNo(chapterList.size() + 1);
            if (chapterDTO.getStatus().equals(1)) {
                //如果是直接发布，则需要判断是否之前还存在草稿
                if (chapterList.stream().anyMatch(chapter1 -> chapter1.getStatus().equals(0))) {
                    throw new BusinessException("请先处理之前的章节草稿");
                }
            }
        } else {
            chapter.setChapterNo(1);
        }
        if (chapterDTO.getStatus().equals(0)) {
            //直接保存草稿
            chapterMapper.insert(chapter);
        } else {
            chapter.setStatus(2);
            //建立审批
            Review review = Review.builder().reviewType(ReviewEnum.CHAPTER.getType())
                    .createdEmail(userInfo.getEmail())
                    .createdUser(userInfo.getNickname())
                    .createdId(userInfo.getId())
                    .reviewResult(0)
                    .mainId(chapter.getId())
                    .mainTitle(chapter.getChapterName())
                    .build();
            reviewMapper.insert(review);
            chapterMapper.insert(chapter);
            updateNovel(chapter);
        }

    }

    /**
     * 编辑章节
     *
     * @param chapterDTO 章节信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editChapter(ChapterDTO chapterDTO) {
        TpUser userInfo = userService.getUserInfo();
        if (ObjectUtils.isEmpty(chapterDTO.getId())) {
            log.error("更新章节必须传id,参数{}", chapterDTO);
            throw new BusinessException("参数有误");
        }
        Chapter byId = chapterMapper.selectById(chapterDTO.getId());
        if (ObjectUtils.isEmpty(byId)) {
            log.error("更新章节传的id有误,章节不存在,参数{}", chapterDTO.getId());
            throw new BusinessException("参数有误");
        }
        Chapter chapter = chapterDTO.doForward();
        //markdown->html
        chapter.setChapterContentHtml(MarkdownUtils.markdownToHtml(chapter.getChapterContentMarkdown()));
        if (chapterDTO.getStatus().equals(0)) {
            chapterMapper.updateById(chapter);
        } else {
            //现章节状态更新为审核中
            chapter.setStatus(2);
            chapterMapper.updateById(chapter);
            //建立审批
            Review review = Review.builder().reviewType(ReviewEnum.CHAPTER_EDIT.getType())
                    .createdEmail(userInfo.getEmail())
                    .createdUser(userInfo.getNickname())
                    .createdId(userInfo.getId())
                    .reviewResult(0)
                    .mainId(chapter.getId())
                    .mainTitle(chapter.getChapterName() + "-编辑")
                    .build();
            reviewMapper.insert(review);
            //章节编辑前内容入缓存
            redissonHelper.setValue("edit-chapter" + chapter.getId(), byId);

        }

    }

    /**
     * 章节信息变化带动小说信息变化
     *
     * @param chapter 章节
     */
    @Override
    public void updateNovel(Chapter chapter) {
        if (chapter.getStatus().equals(1)) {
            List<Chapter> chapterList = chapterMapper.selectList(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID,
                    chapter.getNovelId()).eq(Chapter.COL_STATUS, 1));
            long count = chapterList.stream().mapToLong(Chapter::getWordNums).sum();
            Novel novel = Novel.builder().id(chapter.getNovelId()).wordNums(count).chapterNums(chapterList.size()).build();
            if (chapter.getChapterNo().equals(1)) {
                novel.setHotNums(System.currentTimeMillis() / 3600000);
            }
            novelMapper.updateById(novel);
        }
    }

    /**
     * 发布章节
     *
     * @param id 章节id
     */
    @Override
    public void publishChapter(Long id) {
        Chapter chapter = chapterMapper.selectById(id);
        if (ObjectUtils.isNotEmpty(chapter)) {
            chapter.setStatus(1);
            chapterMapper.updateById(chapter);
            updateNovel(chapter);
        } else {
            throw new BusinessException("章节不存在");
        }
    }

    /**
     * 读小说
     *
     * @param readDTO 参数
     * @return 读信息
     */
    @Override
    public ReadVO read(ReadDTO readDTO) {
        TpUser userInfo;
        try {
            userInfo = userService.getUserInfo();
            readDTO.setUserId(userInfo.getId());
        } catch (BusinessException e) {
            userInfo = null;
        }
        Novel novel = novelMapper.selectById(readDTO.getNovelId());
        Chapter chapter = chapterMapper.selectById(readDTO.getChapterId());
        Optional.ofNullable(chapter).orElseThrow(() -> new BusinessException("章节不存在"));
        if (!chapter.getStatus().equals(1)) {
            throw new BusinessException("该章节作者正在维护,请稍后阅读");
        }
        ReadVO readVO = new ReadVO();
        ConverterUtil.copyPropertiesIgnoreNull(chapter, readVO);
        if (ObjectUtils.isNotEmpty(userInfo) && novelMapper.readChapterRecordExist(readDTO) < 1) {
            //第一次阅读这一章节
            if (novel.getIsCharge() != 0 && chapter.getChapterNo() >= novel.getIsCharge()) {
                if (userInfo.getGoldCoinNums() < novel.getChargeAmount()) {
                    throw new BusinessException("你的余额已不足够支付下一章的费用,请先充值");
                }
                //付费阅读记录
                novelMapper.read(novel.getId(), userInfo.getId(), chapter.getId(), 0, new Date());
                //用户金币扣减
                userInfo.setGoldCoinNums(userInfo.getGoldCoinNums() - novel.getChargeAmount());
                tpUserMapper.updateById(userInfo);
                userService.updateRedisUser(userInfo);
                //作者金币+
                charge(novel.getAuthorId(), novel.getChargeAmount());
            } else {
                //免费阅读
                novelMapper.read(novel.getId(), userInfo.getId(), chapter.getId(), 1, new Date());
            }
        } else {
            //免费阅读
            if (ObjectUtils.isNotEmpty(userInfo)) {
                novelMapper.read(novel.getId(), userInfo.getId(), chapter.getId(), 1, new Date());
            } else {
                if (novel.getIsCharge() != 0 && chapter.getChapterNo() >= novel.getIsCharge()) {
                    //收费
                    throw new BusinessException("该章节为付费章节,请先登录");
                }
            }
        }
        Integer chapterNo = chapter.getChapterNo();
        //获取相邻章节信息
        Chapter preChapter = chapterMapper.selectOne(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, readDTO.getNovelId())
                .eq(Chapter.COL_CHAPTER_NO, chapterNo - 1).eq(Chapter.COL_STATUS, 1));
        Chapter nextChapter = chapterMapper.selectOne(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, readDTO.getNovelId())
                .eq(Chapter.COL_CHAPTER_NO, chapterNo + 1).eq(Chapter.COL_STATUS, 1));
        if (ObjectUtils.isNotEmpty(preChapter)) {
            readVO.setPreviousChapterId(preChapter.getId());
            readVO.setPreviousChapterName(preChapter.getChapterName());
        }
        if (ObjectUtils.isNotEmpty(nextChapter)) {
            readVO.setNextChapterId(nextChapter.getId());
            readVO.setNextChapterName(nextChapter.getChapterName());
        }
        return readVO;
    }

    /**
     * 收费
     *
     * @param userId 用户id
     * @param amount 金额
     */
    @Override
    public void charge(Long userId, Long amount) {
        RLock lock = redissonHelper.getLock("amount" + userId);
        try {
            if (lock.tryLock(100, 10000, TimeUnit.MILLISECONDS)) {
                try {
                    TpUser tpUser = tpUserMapper.selectById(userId);
                    tpUser.setGoldCoinNums(tpUser.getGoldCoinNums() + amount);
                    tpUserMapper.updateById(tpUser);
                } finally {
                    lock.unlock();
                }
            } else {
                charge(userId, amount);
            }
        } catch (InterruptedException e) {
            log.error("用户金币增加操作失败 authorId:{}", userId, e);
        }
    }

    /**
     * 小说阅读数增加
     *
     * @param readDTO 参数
     */
    @Override
    public void readNum(ReadDTO readDTO) {
        addReadNum(readDTO.getNovelId());
        //热度变化
        applicationEventPublisher.publishEvent(HotEvent.builder().novelId(readDTO.getNovelId())
                .hotNums(1000L).build());
    }

    /**
     * 增加小说阅读数
     *
     * @param novelId 小说id
     */
    public void addReadNum(Long novelId) {
        RLock lock = redissonHelper.getLock("add-read-num" + novelId);
        try {
            if (lock.tryLock(100, 10000, TimeUnit.MILLISECONDS)) {
                try {
                    //增加热度和阅读数
                    Novel novel = novelMapper.selectById(novelId);
                    novel.setBrowseNums(novel.getBrowseNums() + 1);
                    novelMapper.updateById(novel);
                } finally {
                    lock.unlock();
                }
            } else {
                addReadNum(novelId);
            }
        } catch (InterruptedException e) {
            log.error("增加阅读数操作失败 novelId:{}", novelId, e);
        }
    }


    /**
     * 加入书架
     *
     * @param novelId 小说id
     */
    @Override
    public void subscribe(Long novelId) {
        TpUser userInfo = userService.getUserInfo();
        Subscribe subscribe = Subscribe.builder().userId(userInfo.getId()).novelId(novelId).build();
        try {
            subscribeMapper.insert(subscribe);
        } catch (Exception e) {
            log.error("已经追过了", e);
            throw new BusinessException("已经追过了");
        }
        addSubscribeNum(novelId, userInfo.getId());
        //热度变化
        applicationEventPublisher.publishEvent(HotEvent.builder().novelId(novelId)
                .hotNums(2000L).build());
    }

    /**
     * 增加小说订阅数
     *
     * @param novelId 小说id
     * @param userId  用户id
     */
    public void addSubscribeNum(Long novelId, Long userId) {
        RLock lock = redissonHelper.getLock("add-subscribe-num" + novelId);
        try {
            if (lock.tryLock(100, 10000, TimeUnit.MILLISECONDS)) {
                try {
                    Novel novel = novelMapper.selectById(novelId);
                    novel.setSubscribeNums(novel.getSubscribeNums() + 1);
                    novelMapper.updateById(novel);
                } finally {
                    lock.unlock();
                }
            } else {
                addSubscribeNum(novelId, userId);
            }
        } catch (InterruptedException e) {
            log.error("用户 {} 追书操作失败 novelId:{}", userId, novelId, e);
        }
    }

    /**
     * 移除书架
     *
     * @param novelId 小说id
     */
    @Override
    public void cancelSubscribe(Long novelId) {
        TpUser userInfo = userService.getUserInfo();
        int delete = subscribeMapper.delete(new QueryWrapper<Subscribe>().eq(Subscribe.COL_NOVEL_ID, novelId)
                .eq(Subscribe.COL_USER_ID, userInfo.getId()));
        if (delete > 0) {
            cancelSubscribeNum(novelId, userInfo.getId());
        } else {
            throw new BusinessException("还没追过");
        }
        //热度变化
        applicationEventPublisher.publishEvent(HotEvent.builder().novelId(novelId)
                .hotNums(-2000L).build());
    }

    /**
     * 取消小说阅读数
     *
     * @param novelId 小说id
     * @param userId  用户id
     */
    private void cancelSubscribeNum(Long novelId, Long userId) {
        RLock lock = redissonHelper.getLock("add-subscribe-num" + novelId);
        try {
            if (lock.tryLock(100, 10000, TimeUnit.MILLISECONDS)) {
                try {
                    Novel novel = novelMapper.selectById(novelId);
                    novel.setSubscribeNums(novel.getSubscribeNums() - 1);
                    novelMapper.updateById(novel);
                } finally {
                    lock.unlock();
                }
            } else {
                cancelSubscribeNum(novelId, userId);
            }
        } catch (InterruptedException e) {
            log.error("用户 {} 取消追书操作失败 novelId:{}", userId, novelId, e);
        }
    }

    /**
     * 评分
     *
     * @param novelId 小说id
     * @param score   分数
     */
    @Override
    public void score(Long novelId, String score) {
        TpUser userInfo = userService.getUserInfo();
        if (novelMapper.readRecordExist(novelId, userInfo.getId()) < 1) {
            throw new BusinessException("只有阅读过小说能进行评价");
        }
        Novel novel = novelMapper.selectById(novelId);
        if (ObjectUtils.isEmpty(novel)) {
            throw new BusinessException("要评价的小说不存在");
        }
        ScoreRecord oldRecord = scoreRecordMapper.selectOne(new QueryWrapper<ScoreRecord>()
                .eq(ScoreRecord.COL_NOVEL_ID, novelId).eq(ScoreRecord.COL_USER_ID, userInfo.getId()));
        BigDecimal oldRecords = BigDecimal.ZERO;
        if (ObjectUtils.isNotEmpty(oldRecord)) {
            oldRecords = oldRecord.getScore();
        }
        scoreNum(novel, score, userInfo.getId(), oldRecords);
        ScoreRecord scoreRecord = ScoreRecord.builder().score(new BigDecimal(score))
                .novelId(novelId).userId(userInfo.getId()).build();

        if (ObjectUtils.isEmpty(oldRecord)) {
            scoreRecordMapper.insert(scoreRecord);
        } else {
            scoreRecord.setId(oldRecord.getId());
            scoreRecordMapper.updateById(scoreRecord);
        }

    }

    private void scoreNum(Novel novel, String score, Long userId, BigDecimal oldRecords) {
        RLock lock = redissonHelper.getLock("score" + novel.getId());
        try {
            if (lock.tryLock(100, 10000, TimeUnit.MILLISECONDS)) {
                try {
                    BigDecimal score1 = novel.getScore();
                    if (ObjectUtils.isEmpty(score1)) {
                        score1 = BigDecimal.ZERO;
                    }
                    Integer scoreNums = novel.getScoreNums();
                    BigDecimal allScore = score1.multiply(new BigDecimal(String.valueOf(scoreNums)));
                    BigDecimal newAllScore = allScore.add(new BigDecimal(score));
                    if (oldRecords.compareTo(BigDecimal.ZERO) != 0) {
                        newAllScore = newAllScore.subtract(oldRecords);
                        scoreNums--;
                    }
                    BigDecimal newScore = newAllScore.divide(new BigDecimal(String.valueOf(scoreNums + 1)), 2, RoundingMode.HALF_UP);
                    novel.setScore(newScore);
                    novel.setScoreNums(scoreNums + 1);
                    novelMapper.updateById(novel);
                } finally {
                    lock.unlock();
                }
            } else {
                scoreNum(novel, score, userId, oldRecords);
            }
        } catch (InterruptedException e) {
            log.error("用户 {} 评分操作失败 novelId:{}", userId, novel.getId(), e);
        }
    }

    /**
     * 获取小说所有章节草稿
     *
     * @param novelId 小说id
     * @return 草稿
     */
    @Override
    public List<ChapterVO> getAllChapterDraft(Long novelId) {
        List<Chapter> chapterList = chapterMapper.selectList(
                new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, novelId).eq(Chapter.COL_STATUS, 0)
                        .orderByDesc(Chapter.COL_CHAPTER_NO));
        return ConverterUtil.convertList(chapterList);
    }

    /**
     * 获取所有的章节
     *
     * @param novelId 小说id
     * @param sort    排序字段
     * @return 结果
     */
    @Override
    public List<ChapterVO> getAllChapter(Long novelId, Integer sort) {
        QueryWrapper<Chapter> eq = new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, novelId).eq(Chapter.COL_STATUS, 1);
        if (sort == 0) {
            //升序
            eq.orderByAsc(Chapter.COL_CHAPTER_NO);
        } else {
            //降序
            eq.orderByDesc(Chapter.COL_CHAPTER_NO);
        }
        List<Chapter> chapterList = chapterMapper.selectList(eq);
        return ConverterUtil.convertList(chapterList);
    }

    /**
     * 我的小说-作者
     *
     * @param pageParams 参数
     * @return 结果
     */
    @Override
    public PageResult<Novel> getMyBookList(PageParams pageParams) {
        TpUser userInfo = userService.getUserInfo();
        return new PageResult<>(novelMapper.selectPage(new Page<>(pageParams.getPageNum(), pageParams.getPageSize(), true),
                new QueryWrapper<Novel>().eq(Novel.COL_AUTHOR_ID, userInfo.getId())
                        .orderByDesc(Novel.COL_UPDATED_TIME).orderByAsc(Novel.COL_STATUS)));
    }

    /**
     * 我的书架
     *
     * @param pageParams 参数
     * @return 结果
     */
    @Override
    public PageResult<BookSelfVO> getMyBookSelf(PageParams pageParams) {
        TpUser userInfo = userService.getUserInfo();
        Page<BookSelfVO> pageBookSelfVO = novelMapper.getMyBookSelf(new Page<>(pageParams.getPageNum()
                , pageParams.getPageSize()), userInfo.getId());
        return new PageResult<>(pageBookSelfVO);
    }

    /**
     * 是否存在草稿
     *
     * @param novelId 小说id
     * @return 结果
     */
    @Override
    public boolean existDraft(Long novelId) {
        Long count = chapterMapper.selectCount(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, novelId).eq(Chapter.COL_STATUS, 0));
        return count > 0;
    }

    /**
     * 章节列表-分页
     *
     * @param chapterPageDTO 参数
     * @return 结果
     */
    @Override
    public PageResult<ChapterVO> chapterList(ChapterPageDTO chapterPageDTO) {
        QueryWrapper<Chapter> eq = new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, chapterPageDTO.getNovelId())
                .in(Chapter.COL_STATUS, 1, 2, 3);
        if (ObjectUtils.isNotEmpty(chapterPageDTO.getChapterNo())) {
            eq.eq(Chapter.COL_CHAPTER_NO, chapterPageDTO.getChapterNo());
        }
        if (ObjectUtils.isNotEmpty(chapterPageDTO.getChapterName())) {
            eq.like(Chapter.COL_CHAPTER_NAME, chapterPageDTO.getChapterName());
        }
        eq.orderByDesc(Chapter.COL_CHAPTER_NO);
        Page<Chapter> chapterPage = chapterMapper.selectPage(new Page<>(chapterPageDTO.getPageNum(),
                chapterPageDTO.getPageSize(), true), eq);
        List<Chapter> records = chapterPage.getRecords();
        List<ChapterVO> chapterVOList = ConverterUtil.convertList(records);
        return new PageResult<>(
                chapterVOList, (int) chapterPage.getTotal(), (int) chapterPage.getSize(), (int) chapterPage.getCurrent());

    }

    /**
     * 章节详情
     *
     * @param chapterId 章节id
     * @return 结果
     */
    @Override
    public Chapter getChapter(Long chapterId) {
        return chapterMapper.selectById(chapterId);
    }

    /**
     * 设置收费章节
     *
     * @param charge 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setCharge(ChargeDTO charge) {
        TpUser userInfo = userService.getUserInfo();
        if (!userInfo.getIsSign().equals(1)) {
            throw new BusinessException("只有签约作者可以设置收费章节");
        }
        Novel novel = novelMapper.selectById(charge.getNovelId());
        novel.setIsCharge(charge.getChapterNo());
        novel.setChargeAmount(charge.getAmount());
        novelMapper.updateById(novel);
    }

    /**
     * 搜索
     *
     * @param query 搜索条件
     * @return 搜索结果
     */
    @Override
    public List<SearchVO> search(String query) {
        List<Novel> novelList = novelMapper.selectList(new QueryWrapper<Novel>().like(Novel.COL_TITLE, query).last("limit 10"));
        return novelList.stream().map(novel -> {
            SearchVO searchVO = new SearchVO();
            ConverterUtil.copyPropertiesIgnoreNull(novel, searchVO);
            return searchVO;
        }).collect(Collectors.toList());
    }

    /**
     * 完结小说
     *
     * @param novelId 小说id
     */
    @Override
    public void finish(Long novelId) {
        Novel novel = novelMapper.selectById(novelId);
        if (!novel.getStatus().equals(0)) {
            throw new BusinessException("小说信息有误");
        }
        List<Chapter> chapters = chapterMapper.selectList(new QueryWrapper<Chapter>().eq(Chapter.COL_NOVEL_ID, novel.getId()));
        if (!chapters.stream().allMatch(chapter -> chapter.getStatus().equals(1))) {
            throw new BusinessException("你有章节还未完成");
        }
        novel.setStatus(1);
        novelMapper.updateById(novel);
    }
}
